#include <WinSock2.h>
#include <WS2tcpip.h>
#include <iostream>

#pragma comment(lib, "Ws2_32.lib")

#define DEFAULT_PORT "27015" // 服务器监听的端口
#define DEFAULT_BUFLEN 512  // 缓冲区大小

int main() 
{
    /* 初始化 Winsock */
    WSADATA wsaData;
    int iResult;

    // 调用 WSAStartup 函数以启用 WS2_32.dll 库
    iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if(iResult != 0)
    {
        std::cout << "WSAStartup failed: " << iResult << std::endl;
        return 1;
    }

    /* 创建套接字 */
    // 获取套接字地址
    addrinfo *result = NULL, hints;

    ZeroMemory(&hints, sizeof(hints));
    hints.ai_family = AF_INET; // IPv4
    hints.ai_socktype = SOCK_STREAM; // TCP
    hints.ai_protocol = IPPROTO_TCP; // TCP
    hints.ai_flags = AI_PASSIVE; // 允许使用本地地址

    // 调用 getaddrinfo 函数以获取本地地址信息
    iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result);
    if(iResult != 0)
    {
        std::cout << "getaddrinfo failed: " << iResult << std::endl;
        WSACleanup();
        return 1;
    }

    // 创建套接字对象
    SOCKET listenSocket = INVALID_SOCKET;
    listenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
    if(listenSocket == INVALID_SOCKET)
    {
        //  WSAGetLastError 返回与上次发生的错误关联的错误号
        std::cout << "Error at socket(): " << WSAGetLastError() << std::endl;
        freeaddrinfo(result);
        WSACleanup();
        return 1;
    }

    /* 绑定套接字对象和套接字地址 */
    iResult = bind(listenSocket, result->ai_addr, (int)result->ai_addrlen);
    if(iResult == SOCKET_ERROR)
    {
        std::cout << "bind failed with error: " << WSAGetLastError() << std::endl;
        freeaddrinfo(result);
        closesocket(listenSocket);
        WSACleanup();
        return 1;
    }
    // 调用 bind() 函数之后，不再需要 getaddrinfo() 函数返回的地址信息
    // 所以调用 freeaddrinfo() 函数，释放内存
    freeaddrinfo(result);

    /* 监听套接字 */
    std::cout << "server waiting for client connection..." << std::endl;
    iResult = listen(listenSocket, SOMAXCONN);
    if(iResult == SOCKET_ERROR)
    {
        std::cout << "listen failed with error: " << WSAGetLastError() << std::endl;
        closesocket(listenSocket);
        WSACleanup();
        return 1;
    }
    
    /* 接受客户端连接 */
    SOCKET clientSocket = INVALID_SOCKET;
    sockaddr* clientAddr = NULL;
    int* clientAddrLen = NULL;
    clientSocket = accept(listenSocket, clientAddr, clientAddrLen);
    if(clientSocket == INVALID_SOCKET)
    {
        std::cout << "accept failed with error: " << WSAGetLastError() << std::endl;
        closesocket(listenSocket);
        WSACleanup();
        return 1;
    }
    // 调用 accept() 函数之后，此示例不再需要 listenSocket 套接字
    // 调用 closesocket() 函数，关闭套接字
    closesocket(listenSocket);
    std::cout << "Client connected" << std::endl;

    /* 接收和发送数据 */
    char recvbuf[DEFAULT_BUFLEN]; // 缓冲区
    int iRecvResult; // 接收结果
    int iSendResult; // 发送结果
    int recvbuflen = DEFAULT_BUFLEN; // 指定需要接收的字节大小

    // 持续接收数据，直到连接关闭
    do{
        // 从连接的客户端接收数据
        // 返回接收的字节数或错误值
        iRecvResult = recv(clientSocket, recvbuf, recvbuflen, 0);
        // 检查接收结果
        if(iRecvResult > 0)
        {
            std::cout << "Bytes received: " << iRecvResult << std::endl;
            std::cout << "Received message from client: " << recvbuf << std::endl;

            // 将接收到的数据发回给连接的客户端（回显）
            // 返回接收的字节数或错误值
            iSendResult = send(clientSocket, recvbuf, iRecvResult, 0);
            if(iSendResult == SOCKET_ERROR)
            {
                std::cout << "send failed with error: " << WSAGetLastError() << std::endl;
                closesocket(clientSocket);
                WSACleanup();
                return 1;
            }
            std::cout << "Bytes sent: " << iSendResult << std::endl;
        }else if(iRecvResult == 0) // 如果等于0，则表示连接关闭
        {
            std::cout << "Connection closed" << std::endl;
        }
        else // 如果小于0，则表示发生错误
        {
            std::cout << "recv failed with error: " << WSAGetLastError() << std::endl;
            closesocket(clientSocket);
            WSACleanup();
            return 1;
        }

    }while(iRecvResult > 0);

    /* 断开并关闭套接字 */
    // 关闭客户端的发送连接，使客户端不再发送数据，以确保传输数据不会丢失
    iResult = shutdown(clientSocket, SD_SEND);
    if(iResult == SOCKET_ERROR)
    {
        std::cout << "shutdown failed with error: " << WSAGetLastError() << std::endl;
        closesocket(clientSocket);
        WSACleanup();
        return 1;
    }

    // 关闭套接字（完全关闭并释放资源）
    closesocket(clientSocket);
    WSACleanup();

    std::cout << "server: bye"<< std::endl;
    return 0;
}